package com.linkoog.devtools.toolwindow_manager;

import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;

/**
 *
 */
public class ToolWindowManagerProjectComponentImpl implements ToolWindowManagerProjectComponent {
    private static final Timer TIMER = new Timer(true);

    private final Map<String, AvailabilityPreference> toolWindowDefaults = new HashMap<String, AvailabilityPreference>();
    private PreferredAvailabilitiesView configurationComponent;
    private final Object lock = new Object();
    private final Project project;

    public ToolWindowManagerProjectComponentImpl(Project project) {
        this.project = project;
    }

    private void applyPreferencesFrom(@NotNull List<ToolWindowPreference> preferencesToApply) {
        final ToolWindowPreferenceApplier toolWindowPreferenceApplier = new ToolWindowPreferenceApplier(project);

        toolWindowPreferenceApplier.applyPreferencesFrom(preferencesToApply);
    }

    @NotNull
    public List<ToolWindowPreference> getDefaultAvailabilities() {
        final List<ToolWindowPreference> result = new ArrayList<ToolWindowPreference>();

        for (final Map.Entry<String, AvailabilityPreference> toolWindowDefault : toolWindowDefaults.entrySet()) {
            result.add(new ToolWindowPreference(toolWindowDefault.getKey(), toolWindowDefault.getValue()));
        }

        return result;
    }

    @Nullable
    public AvailabilityPreference getDefaultAvailability(@NotNull String id) {
        return toolWindowDefaults.get(id);
    }

    @NotNull
    public List<ToolWindowPreference> getPreferredAvailabilities() {
        final List<ToolWindowPreference> result = new ArrayList<ToolWindowPreference>();

        synchronized (lock) {
            SortedMap<String, AvailabilityPreference> toolWindowPreferences = ToolwindowManagerPluginSettings.getInstance(project).getToolWindowPreferences();
            for (final Map.Entry<String, AvailabilityPreference> toolWindowDefault : toolWindowPreferences.entrySet()) {
                result.add(new ToolWindowPreference(toolWindowDefault.getKey(), toolWindowDefault.getValue()));
            }
        }

        return result;
    }

    // Implement BaseComponent

    public void disposeComponent() {
    }

    @NotNull
    public String getComponentName() {
        final String componentName = getClass().getPackage().getName();
        return componentName;
    }

    public void initComponent() {
    }

    // Implement ProjectComponent

    public void projectClosed() {
    }

    public void projectOpened() {
        if (project != null && !project.isDefault()) {
            TIMER.schedule(new TimerTask() {
                @Override
                public void run() {
                    SwingUtilities.invokeLater(() -> {
                        final ToolWindowManager manager = ToolWindowManager.getInstance(project);

                        for (final String id : manager.getToolWindowIds()) {
                            final ToolWindow toolWindow = manager.getToolWindow(id);

                            if (toolWindow != null) {
                                final boolean isAvailable = toolWindow.isAvailable();

                                toolWindowDefaults.put(id, isAvailable ? AvailabilityPreference.AVAILABLE : AvailabilityPreference.UNAVAILABLE);
                            }
                        }

                        applyPreferencesFrom(getPreferredAvailabilities());
                    });
                }
            }, 5000);
        }
    }


    public JComponent createComponent() {
        synchronized (lock) {
            final ToolWindowManager manager = ToolWindowManager.getInstance(project);
            SortedMap<String, AvailabilityPreference> toolWindowPreferences = ToolwindowManagerPluginSettings.getInstance(project).getToolWindowPreferences();
            for (final String id : manager.getToolWindowIds()) {
                if (toolWindowPreferences.get(id) == null) {
                    final ToolWindow toolWindow = manager.getToolWindow(id);

                    if (toolWindow != null) {
                        toolWindowPreferences.put(id, AvailabilityPreference.UNAFFECTED);
                    }
                }

                if (toolWindowDefaults.get(id) == null) {
                    final ToolWindow toolWindow = manager.getToolWindow(id);

                    if (toolWindow != null) {
                        final boolean isAvailable = toolWindow.isAvailable();

                        toolWindowDefaults.put(id, isAvailable ? AvailabilityPreference.AVAILABLE : AvailabilityPreference.UNAVAILABLE);
                    }
                }
            }
        }

        configurationComponent = new PreferredAvailabilitiesView(project);

        return configurationComponent;
    }

    public boolean isModified() {
        final List<ToolWindowPreference> editedToolWindowPreferences = configurationComponent.getCurrentViewState();
        SortedMap<String, AvailabilityPreference> toolWindowPreferences = ToolwindowManagerPluginSettings.getInstance(project).getToolWindowPreferences();
        for (final ToolWindowPreference editedToolWindowPreference : editedToolWindowPreferences) {
            if (toolWindowPreferences.get(editedToolWindowPreference.getId()) !=
                    editedToolWindowPreference.getAvailabilityPreference()) {
                return true;
            }
        }

        return false;
    }

    public void apply() throws ConfigurationException {
        final List<ToolWindowPreference> editedToolWindowPreferences = configurationComponent.getCurrentViewState();

        synchronized (lock) {
            SortedMap<String, AvailabilityPreference> toolWindowPreferences = ToolwindowManagerPluginSettings.getInstance(project).getToolWindowPreferences();
            toolWindowPreferences.clear();

            for (final ToolWindowPreference toolWindowPreference : editedToolWindowPreferences) {
                if (toolWindowPreference != null) {
                    toolWindowPreferences.put(toolWindowPreference.getId(), toolWindowPreference.getAvailabilityPreference());
                }
            }

            applyPreferencesFrom(editedToolWindowPreferences);
        }
    }

    public void reset() {
        if (configurationComponent != null) {
            configurationComponent.reset();
        }
    }

    public void disposeUIResources() {
    }
}
